use std::cell::RefCell;
use std::rc::Rc;

use ash::vk;
use ash::vk::BufferCreateInfo;
use ash::vk::Framebuffer;
use ash::vk::ImageView;

use ash::vk::RayTracingPipelineCreateInfoKHR;

use crate::utils::constant::MAX_FRAMES_IN_FLIGHT;

#[derive(Clone)]
pub struct GpuBuffer {
    pub buffer: vk::Buffer,
    pub memory: vk::DeviceMemory
}
pub struct Node {
    pub name: String,
    pub index: usize,
    pub skin : i32,
    pub child: Vec<Rc<RefCell<Node>>>,
    pub parent: Option<Rc<RefCell<Node>>>,
    pub transform: gltf::scene::Transform,
}
impl Node {
    pub fn new(index: usize) -> Self {
        Self {
            name: String::from(""),
            index: index,
            skin: -1,
            child: vec![],
            parent: None,
            transform: gltf::scene::Transform::Matrix { 
                matrix: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ] 
            }
        }
    }
}
impl Default for Node {
    fn default() -> Self {
        Self {
            name: String::from(""),
            index: 0,
            skin: -1,
            child: vec![],
            parent: None,
            transform: gltf::scene::Transform::Matrix { 
                matrix: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ] 
            }
        }
    }
}

pub struct A<'a> {
    int: &'a i32
}

#[derive(Clone)]
pub struct SkinSSBO {
    pub buffer: Vec<ash::vk::Buffer>,
    pub device_memory: Vec<ash::vk::DeviceMemory>,
    pub mapped_handle: Vec<*mut [[f32; 4]; 4]>
}
pub struct Skin {
    pub name: String,
    pub joints: Vec<Rc<RefCell<Node>>>,
    pub inverse_bind_matrices: Vec<[[f32;4];4]>,
    pub ssbo: SkinSSBO
}
pub enum ChannelOutputType {
    Translation([f32; 3]),
    Rotation([f32; 4]),
    Scale([f32; 3]),
    MorphTargetWeight(f32)
}
pub struct Channel {
    pub node: Rc<RefCell<Node>>,
    pub path: gltf::animation::Property,
    pub inputs: Vec<f32>,
    pub outputs: Vec<ChannelOutputType>,
    pub interpolation: gltf::animation::Interpolation
}
pub struct Animation {
    pub name: String,
    pub channels: Vec<Channel>,
    pub animation_time: f32
}

#[derive(Clone)]
pub struct UniformBuffer<T> {
    pub buffer: Vec<vk::Buffer>,
    pub device_memory: Vec<vk::DeviceMemory>,
    pub mapped_handle: Vec<*mut T>
}
impl<T> UniformBuffer<T> {
    pub fn release_resource(&self, vulkan_rhi: &VulkanRHI) {
        unsafe {
            for buffer in &self.buffer {
                vulkan_rhi.logic_device.destroy_buffer(*buffer, None)
            }
            for device_memory in &self.device_memory {
                vulkan_rhi.logic_device.unmap_memory(*device_memory);
                vulkan_rhi.logic_device.free_memory(*device_memory, None);
            }
        };
    }
}

#[derive(Clone)]
pub struct Texture {
    pub image: ash::vk::Image,
    pub device_memory: ash::vk::DeviceMemory,
    pub image_view: ash::vk::ImageView,
    pub sampler: ash::vk::Sampler
}
impl Texture {
    pub fn load(vulkan_rhi: &VulkanRHI, path: String) -> Result<Self, Box<dyn std::error::Error>> {
        let image_raw = image::open(path)?;
        let (image_width, image_height) = (image_raw.width(), image_raw.height());
        let image = match &image_raw {
            image::DynamicImage::ImageLuma8(_)
            | image::DynamicImage::ImageRgb8(_) => image_raw.to_rgba8().into_raw(),
            image::DynamicImage::ImageLumaA8(_)
            | image::DynamicImage::ImageRgba8(_) 
            | &_ => image_raw.as_bytes().to_vec(),
        };
        let _image_size = image.len() as u64;
        
        Ok(vulkan_rhi.create_texture_from_buffer_v2(&image, image_width, image_height, &vulkan_rhi.graphics_queue))
    }
}

pub struct QueueFamilyIndices {
    pub graphics_family: Option<u32>,
    pub present_family: Option<u32>
}
pub struct SwapChainStuff {
    pub swapchain_loader: ash::extensions::khr::Swapchain,
    pub swapchain: vk::SwapchainKHR,
    pub swapchain_images: Vec<vk::Image>,
    pub swapchain_format: vk::Format,
    pub swapchain_extent: vk::Extent2D,
}

#[repr(usize)]
pub enum DescriptorType {
    PerFrame,
    PerDrawcall,
    PerMaterial,
    PerDrawcallPerMesh
}

pub struct SwapChainSupportDetails {
    pub capabilities: vk::SurfaceCapabilitiesKHR,
    pub formats: Vec<vk::SurfaceFormatKHR>,
    pub present_modes: Vec<vk::PresentModeKHR>
}

impl QueueFamilyIndices {
    pub fn is_complete(&self) -> bool {
        self.graphics_family.is_some() && self.present_family.is_some()
    }
}
pub struct SurfaceStuff {
    pub surface_loader: ash::extensions::khr::Surface,
    pub surface: vk::SurfaceKHR,
}

#[derive(Default)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub uv: [f32; 2],
    pub color: [f32; 3],
    pub joint_index: [u16; 4],
    pub joint_weight: [f32; 4]
}

pub struct PerFrameUniformData {
    pub view: cgmath::Matrix4<f32>,
    pub proj: cgmath::Matrix4<f32>,
}

#[derive(Clone)]
pub struct PerObjectUniformData {
    pub model: cgmath::Matrix4<f32>,
    pub is_animated: f32,
}
pub struct VulkanRHI {
    // Vulkan
    pub entry: ash::Entry,
    pub instance: ash::Instance,
    pub debug_utils_loader: ash::extensions::ext::DebugUtils,
    pub debug_messenger: vk::DebugUtilsMessengerEXT,
    pub physical_device: vk::PhysicalDevice,
    pub logic_device: ash::Device,
    pub graphics_queue: vk::Queue,
    pub present_queue: vk::Queue,
    
    pub surface_stuff: SurfaceStuff,
    pub swapchain_stuff: SwapChainStuff,

    pub swapchain_image_views: Vec<ImageView>,
    pub pipeline_layout: vk::PipelineLayout,
    pub render_pass: vk::RenderPass,
    pub graphics_pipelines: Vec<vk::Pipeline>,
    pub framebuffers: Vec<Framebuffer>,
    pub command_pool: vk::CommandPool,

    pub depth_image: vk::Image,
    pub depth_image_memory: vk::DeviceMemory,
    pub depth_image_view: vk::ImageView,

    pub command_buffers: Vec<vk::CommandBuffer>,
    pub image_available_semaphores: Vec<vk::Semaphore>,
    pub render_finished_semaphores: Vec<vk::Semaphore>,
    pub in_flight_fences: Vec<vk::Fence>,

    pub descriptor_set_layouts: Vec<vk::DescriptorSetLayout>,
    pub descriptor_pool: vk::DescriptorPool,

    pub null_uniform_buffer: vk::Buffer,
    pub null_stroage_buffer: vk::Buffer,
}

impl VulkanRHI {
    pub fn new(window: &winit::window::Window) -> Result<Self, Box<dyn std::error::Error>> {
        // 初始化Vulkan Instance
        let entry = unsafe { ash::Entry::load()? };
        let instance = Self::create_instance(&entry);
        // 这部分Create\Destory接口都到DebugUtils上了, 所以Rust实现复杂一些
        let (debug_utils_loader, debug_messenger) = Self::setup_debug_messenger(&entry, &instance);
        // 初始化Surface
        let surface_stuff = Self::create_surface(&entry, &instance, &window);
        // 初始化Physics Device, 教程说其随着Instance Destory会自动触发隐式Destory
        let physical_device = Self::pick_physics_device(&instance, &surface_stuff);
        // 初始化Logic Device
        let (logic_device, graphics_queue, present_queue) = Self::create_logic_device(&instance, physical_device, &surface_stuff);
        // 初始化Swap Chain
        let swapchain_stuff = Self::create_swapchain(&instance, &surface_stuff, &physical_device, &logic_device, window);
        // 初始化Image Views
        let swapchain_image_views = Self::create_image_views(&logic_device, &swapchain_stuff.swapchain_format, &swapchain_stuff.swapchain_images);
        // 初始化Render Pass
        let render_pass = Self::create_render_pass(&instance, &physical_device, &logic_device, &swapchain_stuff);
        // 初始化Descriptor Set Layout
        let descriptor_set_layouts: Vec<vk::DescriptorSetLayout> = Self::create_descriptor_set_layout(&logic_device);
        // 初始化Graphics Pipeline
        let (graphics_pipelines, pipeline_layout) = Self::create_graphics_pipeline(&logic_device, &render_pass, &swapchain_stuff, &descriptor_set_layouts);
        // 初始化Command Pool
        let command_pool = Self::create_command_pool(&instance, &logic_device, &physical_device, &surface_stuff);
        // 初始化Depth
        let (depth_image, depth_image_memory, depth_image_view) = Self::create_depth_resources(&instance, &logic_device, &physical_device, &swapchain_stuff, &command_pool, &graphics_queue);
        // 初始化Frame Buffers
        let framebuffers = Self::create_framebuffers(&logic_device, &swapchain_image_views, &render_pass, &swapchain_stuff, &depth_image_view);
        // 初始化Command Buffer
        let command_buffers = Self::create_command_buffers(&logic_device, &command_pool, MAX_FRAMES_IN_FLIGHT);
        // 初始化同步量
        let (image_available_semaphores, render_finished_semaphores, in_flight_fences) = Self::create_sync_objects(&logic_device);
        // 初始化Descriptor Pool
        let descriptor_pool = Self::create_descriptor_pool(&logic_device);
        // 初始化null buffer
        let null_uniform_buffer = unsafe{ logic_device.create_buffer(&BufferCreateInfo {
                size: 0,
                usage: vk::BufferUsageFlags::UNIFORM_BUFFER,
                ..Default::default()
            }, None).expect("failed to create null buffer")
        };
        let null_storage_buffer = unsafe{ logic_device.create_buffer(&BufferCreateInfo {
                size: 0,
                usage: vk::BufferUsageFlags::STORAGE_BUFFER,
                ..Default::default()
            }, None).expect("failed to create null buffer")
        };
        
        return Ok(
            Self { 
                entry: entry, 
                instance: instance,
                debug_utils_loader: debug_utils_loader,
                debug_messenger: debug_messenger,
                physical_device: physical_device,
                logic_device: logic_device,
                graphics_queue: graphics_queue,
                present_queue: present_queue,
                surface_stuff: surface_stuff,
                swapchain_stuff: swapchain_stuff,
                swapchain_image_views: swapchain_image_views,
                pipeline_layout: pipeline_layout,
                render_pass: render_pass,
                graphics_pipelines: graphics_pipelines,
                framebuffers: framebuffers,
                command_pool: command_pool,

                command_buffers: command_buffers,
                image_available_semaphores: image_available_semaphores,
                render_finished_semaphores: render_finished_semaphores,
                in_flight_fences: in_flight_fences,
                descriptor_set_layouts: descriptor_set_layouts,
                descriptor_pool: descriptor_pool,

                depth_image: depth_image,
                depth_image_memory: depth_image_memory,
                depth_image_view: depth_image_view,

                null_uniform_buffer: null_uniform_buffer,
                null_stroage_buffer: null_storage_buffer
            }
        )
    }
}